#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
// The main programm file. 
/// @TODO: rename p1 and p2 to better names, and from now on make the test related code call 'edge points' to the edges of the vectors as needed

#include <iostream>
#include <cstdlib>
#include <fstream>

#include "Screen.h"
#include "Math.h"
#include "Image.h"
#include "View.h"
#include "Thread.h"
#include "VeinWalker.h"
#include "RunFinder.h"
#include "MainVeinFinder.h"
#include "ArgParser.h"
#include "JunctionFinder.h"
#include "ChildVeinFinder.h"
#include "Debug.h"

#define MAIN_VEIN_JUNCTION_MIN_LENGTH 2 
#define MAIN_VEIN_JUNCTION_90VEIN_MIN_LENGTH 3.5
#define MAIN_VEIN_JUNCTION_90VEIN_MIN_THICKNESS (1.0/10.0)
#define MAIN_VEIN_JUNCTION_N90VEIN_MAX_THICKNESS 3

// variables used for normal mode
Thread *g_pEventHandlerThread;
Mutex g_mutex;
ConditionVariable g_cond;
SDLKey g_key;
bool g_bKeyPressed = false;


void *EventThread(void*)
{
	Screen::Init();
	SDL_Event event;
	event.type = SDL_NOEVENT;
	while(SDL_WaitEvent(&event)) {
		if (event.type == SDL_QUIT) 
			exit(0);
		else if (event.type == SDL_KEYDOWN) {
			g_mutex.Lock();
			g_key = event.key.keysym.sym;
			g_bKeyPressed = true;
			g_cond.NotifyAll();
			g_mutex.Unlock();
		}
	}
	return NULL;
}

void Init(bool bInitSDL)
{
	srand(time(NULL));
	Math::Init();
	if (bInitSDL) {
		(g_pEventHandlerThread = new Thread())->start(EventThread, NULL);
	}
}

void SetMainVeinWalkerCriteria(VeinWalker::Criteria *pCrit, ArgParser *pArgParser)
{
	const bool bNoHillClimbing = pArgParser->IsNoHillClimbing();
	const bool bDetectByMin = false;
	pCrit->m_bDetectByMin = bDetectByMin;
	pCrit->m_bNoHillClimbing = bNoHillClimbing;
	pCrit->m_bFailDueToAngleOutOfRange = pArgParser->IsNoKeepAngleInRange();
	pCrit->m_nMaxPeepDist = 15;
	pCrit->m_nMaxAngleDist = 30;
	pCrit->m_nMaxIterations = -1;
	pCrit->m_nMaxDist = INFINITY;
	pCrit->m_nMinHorizonDist = pArgParser->IsNoHorizonChecks() ? 0 : 6;
	pCrit->m_nMaxAllowedHorizonlessWalks = 10;
	pCrit->m_nLoopPreventEvery = 500;
	pCrit->m_nLoopPreventionDistance = 50;
	pCrit->m_nSegmentForAngleCheck = 20;
}

void SetChildVeinWalkerCriteria(VeinWalker::Criteria *pCrit, ArgParser *pArgParser)
{
	const bool bNoHillClimbing = pArgParser->IsNoHillClimbing();
	const bool bDetectByMin = false;
	pCrit->m_bDetectByMin = bDetectByMin;
	pCrit->m_bNoHillClimbing = bNoHillClimbing;
	pCrit->m_bFailDueToAngleOutOfRange = true;
	pCrit->m_nMaxPeepDist = 15;
	pCrit->m_nMaxAngleDist = 88;
	pCrit->m_nMaxIterations = -1;
	pCrit->m_nMaxDist = INFINITY;
	pCrit->m_nMinHorizonDist = 0;
	pCrit->m_nMaxAllowedHorizonlessWalks = 15;
	pCrit->m_nLoopPreventEvery = 500;
	pCrit->m_nLoopPreventionDistance = 50;
	pCrit->m_nSegmentForAngleCheck = 10;
}

bool FindMainVeinWithUserForcedHints(MainVeinFinder *pFinder, ArgParser *pArgParser)
{
	VeinWalker::Criteria critMainWalker;
	SetMainVeinWalkerCriteria(&critMainWalker, pArgParser);
	if (pArgParser->GetForcedMainVeinCol() != -1 &&
	    pArgParser->GetForcedMainVeinRow() != -1) {
		if (pArgParser->GetForcedMainVeinIndex() != 0) {
			std::cerr << "Can't supply both forced_main_index together with forced_main_row and "   
			             "forced_main_col" << std::endl;
			return false;
		} else {
			Point<S32> ptSpawn(pArgParser->GetForcedMainVeinRow(), 
			                   pArgParser->GetForcedMainVeinCol());
			pFinder->FindMainVeinFromPoint(&critMainWalker, ptSpawn);
			return true;
		}
	} else if (pArgParser->GetForcedMainVeinCol() != -1 ||
	           pArgParser->GetForcedMainVeinRow() != -1) {
		std::cerr << "Can't get forced_main_row without forced_main_col (or vice versa)" << std::endl;
		return false;
	} else {
		pFinder->FindMainVein(&critMainWalker, pArgParser->GetForcedMainVeinIndex() - 1);
		return true;
	}
}

int NormalRun(Image *pImage, ArgParser *pArgParser)
{
	RunFinder<Image> rf(pImage);
	while(!Screen::IsReady()) { sleep(1); }
	{
		if (pArgParser->GetWindowTitle())
			SDL_WM_SetCaption(pArgParser->GetWindowTitle(), NULL);
	}
		
	Screen::ShowImage(pImage);
	MainVeinFinder mvf(pImage);
	VeinWalker::Criteria critChildWalker;
	SetChildVeinWalkerCriteria(&critChildWalker, pArgParser);
	if (!FindMainVeinWithUserForcedHints(&mvf, pArgParser))
		return 1;
	Rect<S32> imageRect;
	Rect<S32> markerRect;
	Screen::GetImageOrViewDrawRect(pImage, &imageRect);
	VeinWalker::Info vi;
	mvf.GetVeinInfo(&vi);
	JunctionFinder jf(pImage);
	JunctionFinder::Criteria jc;
	jc.m_nMinSize = (S32)(vi.m_nAverageThickness * MAIN_VEIN_JUNCTION_MIN_LENGTH);
	jc.m_nMaxJunctionDistance = (S32)(vi.m_nAverageThickness * MAIN_VEIN_JUNCTION_N90VEIN_MAX_THICKNESS);
	JunctionFinder::Info ji;
	jf.GetJunctions(&vi.m_vecStates1, &vi.m_vecStates2, &jc, &ji); 
	
	ChildVeinFinder cvf(pImage);
	cvf.Init(true, &critChildWalker, &vi.m_vecStates1, &vi.m_vecStates2, &ji);
	std::vector< Point <S32> > vecDrawChild;
	ChildVeinFinder::Info infoChild;
	std::cerr << "Note: FILTERING VEINS FOR DEBUG PURPOSES at " 
	          << __FILE__ << ":" << __LINE__ << std::endl;   
	while(cvf.Next(&infoChild) && false /* ORIDEBUG REMOVE ME */) {
//		static S32 s_nIndexDebug;
//		if (++s_nIndexDebug != 2)
//			continue;
//		else
//			Debug::Break();
		std::vector< ViewState >::iterator iterPt;
		std::vector< ViewState > *pVec = &infoChild.m_infoVein.m_vecStates1;
		do {
			for( iterPt = pVec->begin(); iterPt != pVec->end(); ++iterPt) {
				Point<S32> ptDraw;
				ptDraw = iterPt->GetPoint();
				ptDraw.Move(imageRect.Top(), imageRect.Left());
				vecDrawChild.push_back(ptDraw);
			}
			if (pVec == &infoChild.m_infoVein.m_vecStates2) 
				pVec = NULL;
			else if (pVec == &infoChild.m_infoVein.m_vecStates1) 
				pVec = &infoChild.m_infoVein.m_vecStates2;
		}
		while(pVec);
	}
	cvf.Init(false, &critChildWalker, &vi.m_vecStates1, &vi.m_vecStates2, &ji);
	std::vector< Point <S32> > vecDrawChildOpp;
	while(cvf.Next(&infoChild)) {
		std::vector< ViewState >::iterator iterPt;
		std::vector< ViewState > *pVec = &infoChild.m_infoVein.m_vecStates1;
		static S32 s_nOriDebugCounter;
		if (s_nOriDebugCounter == 0)
			std::cerr << "Note: FILTERING VEINS FOR DEBUG PURPOSES at " 
			          << __FILE__ << ":" << __LINE__ << std::endl;
		else if (s_nOriDebugCounter == 3)
			Debug::Stream() << "ORIDEBUG-FOR-CHILD-VEIN-SPLIT-STOP: CHOSEN-BEGIN" << std::endl;
		else if (s_nOriDebugCounter == 4) {
			Debug::Stream() << "ORIDEBUG-FOR-CHILD-VEIN-SPLIT-STOP: CHOSEN-DONE" << std::endl;
			do {
				
				for( iterPt = pVec->begin(); iterPt != pVec->end(); ++iterPt) {		
					Point<S32> ptDraw;
					ptDraw = iterPt->GetPoint();
					ptDraw.Move(imageRect.Top(), imageRect.Left());
					vecDrawChildOpp.push_back(ptDraw);
				}
				if (pVec == &infoChild.m_infoVein.m_vecStates2) 
					pVec = NULL;
				else if (pVec == &infoChild.m_infoVein.m_vecStates1) 
					pVec = &infoChild.m_infoVein.m_vecStates2;
			}
			while(pVec);
		} 
		++s_nOriDebugCounter;
	}
	std::vector< Point <S32> > vecDrawMain;
	std::vector< ViewState >::iterator iter;
	for(iter = vi.m_vecStates1.begin(); iter != vi.m_vecStates2.end(); 
		++iter, iter = (iter != vi.m_vecStates1.end()) ? iter : vi.m_vecStates2.begin()) {
		Point <S32> ptDraw((S32)iter->m_nCenterRow + imageRect.Top(), 
					(S32)iter->m_nCenterCol + imageRect.Left());
		vecDrawMain.push_back(ptDraw);
	}
	
	std::vector< Point <S32> > vecDrawJunction, vecDrawJunction90;
	std::vector< Point <S32> > vecDrawJunctionOpp, vecDrawJunction90Opp;
	{
		std::vector< JunctionFinder::Info::Node > *j_1 = &ji.m_vecJunction, 
		                                          *j_2 = &ji.m_vecJunctionOppositeAngle;
		std::vector< JunctionFinder::Info::Node90 > *j90_1 = &ji.m_vecJunction90,
		                                            *j90_2 = &ji.m_vecJunction90OppositeAngle;
		std::vector< JunctionFinder::Info::Node >::iterator iter;
		std::vector< JunctionFinder::Info::Node90 >::iterator iter90;
		
		for(iter = j_1->begin(); iter != j_1->end(); ++iter)
			for(std::vector< Point < S32 > >::iterator iter2 = iter->m_vecPtDraw.begin(); 
			    iter2 != iter->m_vecPtDraw.end(); ++iter2) 
				vecDrawJunction.push_back(Point<S32>(iter2->Row() + imageRect.Top(), 
				                                     iter2->Col() + imageRect.Left()));
			
		for(iter = j_2->begin(); iter != j_2->end(); ++iter)
			for(std::vector< Point < S32 > >::iterator iter2 = iter->m_vecPtDraw.begin(); 
			    iter2 != iter->m_vecPtDraw.end(); ++iter2) 
				vecDrawJunctionOpp.push_back(Point<S32>(iter2->Row() + imageRect.Top(), 
				                                        iter2->Col() + imageRect.Left()));
		
		for(iter90 = j90_1->begin(); iter90 != j90_1->end(); ++iter90)
			for(std::vector< Point < S32 > >::iterator iter2 = iter90->m_vecPtDraw.begin(); 
			    iter2 != iter90->m_vecPtDraw.end(); ++iter2) 
				vecDrawJunction90.push_back(Point<S32>(iter2->Row() + imageRect.Top(), 
				                                       iter2->Col() + imageRect.Left()));
	
		for(iter90 = j90_2->begin(); iter90 != j90_2->end(); ++iter90)
			for(std::vector< Point < S32 > >::iterator iter2 = iter90->m_vecPtDraw.begin(); 
			    iter2 != iter90->m_vecPtDraw.end(); ++iter2) 
				vecDrawJunction90Opp.push_back(Point<S32>(iter2->Row() + imageRect.Top(), 
				                                          iter2->Col() + imageRect.Left()));
	}
		
	bool bShowMain = false;
	S32 nShowChild = 0;
	S32 nShowJunctions = 0;
	while(1) { 
		g_mutex.Lock();
		while(!g_bKeyPressed)
			g_cond.Wait(&g_mutex);
		g_bKeyPressed = false;
		SDLKey key = g_key;
		g_mutex.Unlock();
		switch(key) {
		case SDLK_m: bShowMain = !bShowMain; break;
		case SDLK_j: ++nShowJunctions; nShowJunctions %= 3; break;
		case SDLK_c: ++nShowChild; nShowChild %= 3; break;
		default:; /* otherwise we get a compile warning? */
		}
		Screen::ShowImage(pImage);
		switch(nShowJunctions) {
		case 1: 
			Screen::DrawPointVector(&vecDrawJunction, 0, 192, 255, 4);
			Screen::DrawPointVector(&vecDrawJunction90, 255, 192, 0, 4);
			break;
		case 2:
			Screen::DrawPointVector(&vecDrawJunctionOpp, 0, 192, 255, 4);
			Screen::DrawPointVector(&vecDrawJunction90Opp, 255, 192, 0, 4);
		}
		if (bShowMain) {
			Screen::DrawPointVector(&vecDrawMain, 255, 128, 255, 1);
			Point<F64> p = mvf.GetSearchStartPoint();
			p.Move(imageRect.Top(), imageRect.Left());
			markerRect.SetCenterWidthHeight(p, 5, 5);
			Screen::DrawRect(&markerRect, 0, 0, 255);
		}
		switch(nShowChild) {
		case 1:
			Screen::DrawPointVector(&vecDrawChild, 255, 0, 0, 1);
			break;
		case 2:
			Screen::DrawPointVector(&vecDrawChildOpp, 255, 0, 0, 1);
		}
		
	}
	while(1) g_pEventHandlerThread->wait();
	return 0;
}

int TestRun(Image *pImage, ArgParser *pArgParser) {
	MainVeinFinder vf(pImage);
	VeinWalker::Criteria critChildWalker;
	SetChildVeinWalkerCriteria(&critChildWalker, pArgParser);
	FindMainVeinWithUserForcedHints(&vf, pArgParser);
	std::ofstream fileReport("report");
	Point<F64> ptSearchStart = vf.GetSearchStartPoint();
	VeinWalker::Info vi;
	vf.GetVeinInfo(&vi);
	JunctionFinder jf(pImage);
	JunctionFinder::Criteria jc;
	jc.m_nMinSize = (S32)(vi.m_nAverageThickness * MAIN_VEIN_JUNCTION_MIN_LENGTH);
	jc.m_nMaxJunctionDistance = (S32)(vi.m_nAverageThickness * MAIN_VEIN_JUNCTION_N90VEIN_MAX_THICKNESS);
	JunctionFinder::Info ji;
	jf.GetJunctions(&vi.m_vecStates1, &vi.m_vecStates2, &jc, &ji); 
	ChildVeinFinder cvf(pImage);
	bool bChildDirection = false;
	std::vector< Point <S32> > vecChildSpawnPoints;
	std::vector< Point <S32> > vecChildSpawnPointsOpp;
	{
		std::vector< Point <S32> > *pVec = &vecChildSpawnPoints;
		do { // this loop only occurs twice
			cvf.Init(bChildDirection, &critChildWalker, 
			         &vi.m_vecStates1, &vi.m_vecStates2, &ji);
			ChildVeinFinder::Info infoChild;
			while(cvf.Next(&infoChild)) {
				Point<S32> ptDraw;
				ptDraw = infoChild.m_stateFirst.GetPoint();
				pVec->push_back(ptDraw);
			}
			bChildDirection = !bChildDirection;
			pVec = &vecChildSpawnPointsOpp;
		}
		while(bChildDirection);
	}
	fileReport << "# Automatic testing report\n";
	fileReport << "#     Search start point\n";
	fileReport << ptSearchStart.Row() << ", " << ptSearchStart.Col() << "\n";
	fileReport << "-----\n";
	fileReport << "#     Vein info\n";
	fileReport << "#         Edge Point 1\n";
	fileReport << vi.m_p1.Row() << ", " << vi.m_p1.Col() << "\n";
	fileReport << "-----\n";
	fileReport << "#         Edge Point 2\n";
	fileReport << vi.m_p2.Row() << ", " << vi.m_p2.Col() << "\n";
	fileReport << "-----\n";
	fileReport << "#         Average Thickness\n";
	fileReport << vi.m_nAverageThickness << "\n";
	fileReport << "-----\n";
	std::vector< JunctionFinder::Info::Node >::iterator iterNode;
	std::vector< JunctionFinder::Info::Node90 >::iterator iter90;
	std::vector< Point < S32 > >::iterator iterPt;
	fileReport << "#     Junctions S32 points (direction 1)\n";
	for(iterNode = ji.m_vecJunction.begin(); iterNode != ji.m_vecJunction.end(); ++iterNode)
		for(iterPt = iterNode->m_vecPtDraw.begin(); iterPt != iterNode->m_vecPtDraw.end(); ++iterPt)
			fileReport << iterPt->Row() << ", " << iterPt->Col() << "\n";
	fileReport << "-----\n";
	fileReport << "#     Junctions S32 points (direction 2)\n";
	for(iterNode = ji.m_vecJunctionOppositeAngle.begin(); 
	    iterNode != ji.m_vecJunctionOppositeAngle.end(); ++iterNode)
		for(iterPt = iterNode->m_vecPtDraw.begin(); iterPt != iterNode->m_vecPtDraw.end(); ++iterPt)
			fileReport << iterPt->Row() << ", " << iterPt->Col() << "\n";
	fileReport << "-----\n";
	fileReport << "#     Junctions S32 points (90 degree, direction 1)\n";
	for(iter90 = ji.m_vecJunction90.begin(); iter90 != ji.m_vecJunction90.end(); ++iter90)
		for(iterPt = iter90->m_vecPtDraw.begin(); iterPt != iter90->m_vecPtDraw.end(); ++iterPt)
			fileReport << iterPt->Row() << ", " << iterPt->Col() << "\n";
	fileReport << "-----\n";
	fileReport << "#     Junctions S32 points (90 degree, direction 2)\n";
	for(iter90 = ji.m_vecJunction90OppositeAngle.begin(); 
	    iter90 != ji.m_vecJunction90OppositeAngle.end(); ++iter90)
		for(iterPt = iter90->m_vecPtDraw.begin(); iterPt != iter90->m_vecPtDraw.end(); ++iterPt)
			fileReport << iterPt->Row() << ", " << iterPt->Col() << "\n";
	fileReport << "-----\n";
	fileReport << "#     Junction spawn points (direction 1)\n";
	for(iterPt = vecChildSpawnPoints.begin(); iterPt != vecChildSpawnPoints.end(); ++iterPt) 
		fileReport << iterPt->Row() << ", " << iterPt->Col() << "\n";
	fileReport << "-----\n";
	fileReport << "#     Junction spawn points (direction 2)\n";
	for(iterPt = vecChildSpawnPointsOpp.begin(); iterPt != vecChildSpawnPointsOpp.end(); ++iterPt)
		fileReport << iterPt->Row() << ", " << iterPt->Col() << "\n";
	fileReport << "-----\n";
	return 0;
}

int InternalRun(Image *pImage, ArgParser *pArgParser)
{
	const char *szOutputFilename;
	if (!(szOutputFilename = pArgParser->GetOutputFilename())) {
		std::cerr << "You must specify an output file with --out" << std::endl;
		return 1;
	}
	S32 nMainVeinColor = pArgParser->GetMainVeinColor();
	S32 nChildVeinColor = pArgParser->GetChildVeinColor();
	S32 nChildVeinOppColor = pArgParser->GetChildVeinOppColor();
	S32 nJunctionColor = pArgParser->GetJunctionColor();
	S32 nJunction90Color = pArgParser->GetJunction90Color();
	S32 nJunctionOppColor = pArgParser->GetJunctionOppColor();
	S32 nJunction90OppColor = pArgParser->GetJunction90OppColor();
	FILE *fileOrder;
	if (pArgParser->GetOrderOutputFileName()) {
		fileOrder = fopen(pArgParser->GetOrderOutputFileName(), "w");
		if (!fileOrder) {
			std::cerr << "Cannot create order output file" << std::endl;
			return 1;
		}
	} else
		fileOrder = NULL;
	MainVeinFinder vf(pImage);
	VeinWalker::Criteria critChildWalker;
	SetChildVeinWalkerCriteria(&critChildWalker, pArgParser);
	FindMainVeinWithUserForcedHints(&vf, pArgParser);
	VeinWalker::Info vi;
	vf.GetVeinInfo(&vi);
	JunctionFinder jf(pImage);
	JunctionFinder::Criteria jc;
	jc.m_nMinSize = (S32)(vi.m_nAverageThickness * MAIN_VEIN_JUNCTION_MIN_LENGTH);
	jc.m_nMaxJunctionDistance = (S32)(vi.m_nAverageThickness * MAIN_VEIN_JUNCTION_N90VEIN_MAX_THICKNESS);
	JunctionFinder::Info ji;
	jf.GetJunctions(&vi.m_vecStates1, &vi.m_vecStates2, &jc, &ji); 
	std::vector< Point <S32> > vecJunction, vecJunction90;
	std::vector< Point <S32> > vecJunctionOpp, vecJunction90Opp;
	{
		std::vector< JunctionFinder::Info::Node > *j_1 = &ji.m_vecJunction, 
		                                          *j_2 = &ji.m_vecJunctionOppositeAngle;
		std::vector< JunctionFinder::Info::Node90 > *j90_1 = &ji.m_vecJunction90,
		                                            *j90_2 = &ji.m_vecJunction90OppositeAngle;
		std::vector< JunctionFinder::Info::Node >::iterator iter;
		std::vector< JunctionFinder::Info::Node90 >::iterator iter90;
		
		for(iter = j_1->begin(); iter != j_1->end(); ++iter)
			for(std::vector< Point < S32 > >::iterator iter2 = iter->m_vecPtDraw.begin(); 
			    iter2 != iter->m_vecPtDraw.end(); ++iter2) 
				vecJunction.push_back(Point<S32>(iter2->Row(), iter2->Col()));
			
		for(iter = j_2->begin(); iter != j_2->end(); ++iter)
			for(std::vector< Point < S32 > >::iterator iter2 = iter->m_vecPtDraw.begin(); 
			    iter2 != iter->m_vecPtDraw.end(); ++iter2) 
				vecJunctionOpp.push_back(Point<S32>(iter2->Row(), iter2->Col()));
		
		for(iter90 = j90_1->begin(); iter90 != j90_1->end(); ++iter90)
			for(std::vector< Point < S32 > >::iterator iter2 = iter90->m_vecPtDraw.begin(); 
			    iter2 != iter90->m_vecPtDraw.end(); ++iter2) 
				vecJunction90.push_back(Point<S32>(iter2->Row(), iter2->Col()));
	
		for(iter90 = j90_2->begin(); iter90 != j90_2->end(); ++iter90)
			for(std::vector< Point < S32 > >::iterator iter2 = iter90->m_vecPtDraw.begin(); 
			    iter2 != iter90->m_vecPtDraw.end(); ++iter2) 
				vecJunction90Opp.push_back(Point<S32>(iter2->Row(), iter2->Col()));
	}
	std::vector< std::vector< Point <S32> > > vecVecChild;
	std::vector< std::vector< Point <S32> > > vecVecChildOpp;
	{
		std::vector< std::vector < Point <S32> > > *pVecVecToAddTo = &vecVecChild;
		ChildVeinFinder cvf(pImage);
		bool bChildDirection = false;
		do { // this loop only occurs twice
			cvf.Init(bChildDirection, &critChildWalker, 
			         &vi.m_vecStates1, &vi.m_vecStates2, &ji);
			ChildVeinFinder::Info infoChild;
			while(cvf.Next(&infoChild)) {
				std::vector< Point <S32> > *pVecToAddTo;
				pVecVecToAddTo->push_back(std::vector< Point<S32> >() );
				pVecToAddTo = &(*pVecVecToAddTo)[pVecVecToAddTo->size() - 1];
				U32 nCount = 0;
				std::vector< ViewState > *pVecToAddFrom = &infoChild.m_infoVein.m_vecStates2;
				std::vector< ViewState >::reverse_iterator iterRevPt;
				for(iterRevPt = pVecToAddFrom->rbegin(); iterRevPt != pVecToAddFrom->rend(); 
				    ++iterRevPt, ++nCount)
					pVecToAddTo->push_back(iterRevPt->GetPoint());
				pVecToAddFrom = &infoChild.m_infoVein.m_vecStates1;
				std::vector< ViewState >::iterator iterPt;
				for(iterPt = pVecToAddFrom->begin(); iterPt != pVecToAddFrom->end(); 
				    ++iterPt, ++nCount)
					pVecToAddTo->push_back(iterPt->GetPoint());
			}
			bChildDirection = !bChildDirection;
			pVecVecToAddTo = &vecVecChildOpp;
		}
		while(bChildDirection);
	}
		
	if (nMainVeinColor != -1) {
		std::vector< ViewState >::iterator iter;
		std::vector< ViewState >::reverse_iterator riter;
		if (fileOrder) fprintf(fileOrder, "main\n");
		for(riter = vi.m_vecStates2.rbegin(); riter != vi.m_vecStates2.rend(); ++riter) {
			pImage->SetPix((S32)riter->m_nCenterRow, (S32)riter->m_nCenterCol, nMainVeinColor);
			if (fileOrder) 
				fprintf(fileOrder, "%d, %d\n", (S32)riter->m_nCenterRow, 
				                               (S32)riter->m_nCenterCol);
		}
		for(iter = vi.m_vecStates1.begin(); iter != vi.m_vecStates1.end(); ++iter) {
			pImage->SetPix((S32)iter->m_nCenterRow, (S32)iter->m_nCenterCol, nMainVeinColor);
			if (fileOrder) 
				fprintf(fileOrder, "%d, %d\n", (S32)iter->m_nCenterRow, 
				                               (S32)iter->m_nCenterCol);
		}
	}
	
	std::vector< JunctionFinder::Info::Node >::iterator iterNode;
	std::vector< JunctionFinder::Info::Node90 >::iterator iter90;
	std::vector< Point < S32 > >::iterator iterPt;
	
	if (nJunctionColor != -1)
	for(iterNode = ji.m_vecJunction.begin(); iterNode != ji.m_vecJunction.end(); ++iterNode)
		for(iterPt = iterNode->m_vecPtDraw.begin(); iterPt != iterNode->m_vecPtDraw.end(); ++iterPt)
			pImage->SetPix((S32)iterPt->Row(), (S32)iterPt->Col(), nJunctionColor);
	
	if (nJunctionOppColor != -1)
	for(iterNode = ji.m_vecJunctionOppositeAngle.begin(); 
	    iterNode != ji.m_vecJunctionOppositeAngle.end(); ++iterNode)
		for(iterPt = iterNode->m_vecPtDraw.begin(); iterPt != iterNode->m_vecPtDraw.end(); ++iterPt)
			pImage->SetPix((S32)iterPt->Row(), (S32)iterPt->Col(), nJunctionOppColor);
	
	if (nJunction90Color != -1)
	for(iter90 = ji.m_vecJunction90.begin(); iter90 != ji.m_vecJunction90.end(); ++iter90)
		for(iterPt = iter90->m_vecPtDraw.begin(); iterPt != iter90->m_vecPtDraw.end(); ++iterPt)
			pImage->SetPix((S32)iterPt->Row(), (S32)iterPt->Col(), nJunction90Color);
	
	if (nJunction90OppColor != -1)
	for(iter90 = ji.m_vecJunction90OppositeAngle.begin(); 
	iter90 != ji.m_vecJunction90OppositeAngle.end(); ++iter90)
		for(iterPt = iter90->m_vecPtDraw.begin(); iterPt != iter90->m_vecPtDraw.end(); ++iterPt)
			pImage->SetPix((S32)iterPt->Row(), (S32)iterPt->Col(), nJunction90OppColor);
	
	if (nChildVeinColor != -1) {
		U32 nChildIndex = 0;
		std::vector< std::vector< Point <S32> > >::iterator iter;
		for(iter = vecVecChild.begin(); iter != vecVecChild.end(); ++iter) {
			if (fileOrder) fprintf(fileOrder, "child_%d\n", nChildIndex++);
			for(iterPt = iter->begin(); iterPt != iter->end(); ++iterPt) {
				pImage->SetPix(iterPt->Row(), iterPt->Col(), nChildVeinColor);
				if (fileOrder) fprintf(fileOrder, "%d, %d\n", iterPt->Row(), iterPt->Col());
			}
		}
	}
	
	if (nChildVeinOppColor != -1) {
		U32 nChildIndex = 0;
		std::vector< std::vector< Point <S32> > >::iterator iter;
		for(iter = vecVecChildOpp.begin(); iter != vecVecChildOpp.end(); ++iter) {
			if (fileOrder) fprintf(fileOrder, "child_opp_%d\n", nChildIndex++);
			for(iterPt = iter->begin(); iterPt != iter->end(); ++iterPt) {
				pImage->SetPix(iterPt->Row(), iterPt->Col(), nChildVeinOppColor);
				if (fileOrder) fprintf(fileOrder,"%d, %d\n", iterPt->Row(), iterPt->Col());
			}
		}
	}
		
	pImage->Save(szOutputFilename);
	if (fileOrder) fclose(fileOrder);
	return 0;
}

/**
 * Main function
 **/
int main(int argc, char *argv[])
{	
	ArgParser parser(argc, argv);
	Image *pImage;
	const char *szFileToOpen;
	if (parser.GetFilesCount())
		pImage = Image::Loader::Load(szFileToOpen = parser.GetFiles()->c_str());
	else	
		pImage = Image::Loader::Load(szFileToOpen = "arabidopsis.pgm");
	if (!pImage)
	{
		std::cerr << "Cannot open " << szFileToOpen << std::endl;
		return 1;
	}
	pImage->ColorSwitch(1, 255); // handle cases where Alex sent a bad image
	if (parser.IsTestRun() && parser.IsInternalRun()) abort();
	if (parser.IsInternalRun()) {
		Init(false);
		return InternalRun(pImage, &parser);
	} else if (parser.IsTestRun()) {
		Init(false);
		return TestRun(pImage, &parser);
	} else {
		Init(true);
		return NormalRun(pImage, &parser);
	}
}
